{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "67cd69c9",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "9bdddd27b8ae4b64b7468d5e5e361f2d",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/4 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "a15f8d9c32be4e7cb5ae3e3d8ff51026",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/4 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "0ae0179918b34772b5b6189640a2b972",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/4 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "f5b25c623ef3472bb60ae51af35f3780",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/4 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "69977a8fe60c4798a1cb23a27fe61e8f",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/4 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "9ba49cb8d2ea46c48a33e36e6282d561",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/4 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "f4e988e812e94bcc897b27011bb9b80d",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/4 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "4ba26953b57b428883fae914eb5a510a",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/4 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "31b1cd54cf0d45c1812f9dc6fa8a5b77",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/4 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "c9d9abda85964466b6bcff0f57a4bfae",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/4 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "ename": "KeyError",
     "evalue": "'低估指标'",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mKeyError\u001b[0m                                  Traceback (most recent call last)",
      "Cell \u001b[1;32mIn[1], line 56\u001b[0m\n\u001b[0;32m     53\u001b[0m low_df \u001b[38;5;241m=\u001b[39m pd\u001b[38;5;241m.\u001b[39mDataFrame(low_industry_list)\n\u001b[0;32m     55\u001b[0m \u001b[38;5;66;03m# 按“低估指标”升序排序，取前10个最低的\u001b[39;00m\n\u001b[1;32m---> 56\u001b[0m top10_low \u001b[38;5;241m=\u001b[39m \u001b[43mlow_df\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msort_values\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m低估指标\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\u001b[38;5;241m.\u001b[39mreset_index(drop\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m)\n\u001b[0;32m     58\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m筛选出最低估的前10个板块：\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m     59\u001b[0m \u001b[38;5;28mprint\u001b[39m(top10_low)\n",
      "File \u001b[1;32mc:\\Python311\\Lib\\site-packages\\pandas\\core\\frame.py:7189\u001b[0m, in \u001b[0;36mDataFrame.sort_values\u001b[1;34m(self, by, axis, ascending, inplace, kind, na_position, ignore_index, key)\u001b[0m\n\u001b[0;32m   7183\u001b[0m     indexer \u001b[38;5;241m=\u001b[39m lexsort_indexer(\n\u001b[0;32m   7184\u001b[0m         keys, orders\u001b[38;5;241m=\u001b[39mascending, na_position\u001b[38;5;241m=\u001b[39mna_position, key\u001b[38;5;241m=\u001b[39mkey\n\u001b[0;32m   7185\u001b[0m     )\n\u001b[0;32m   7186\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(by):\n\u001b[0;32m   7187\u001b[0m     \u001b[38;5;66;03m# len(by) == 1\u001b[39;00m\n\u001b[1;32m-> 7189\u001b[0m     k \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_get_label_or_level_values\u001b[49m\u001b[43m(\u001b[49m\u001b[43mby\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43maxis\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43maxis\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m   7191\u001b[0m     \u001b[38;5;66;03m# need to rewrap column in Series to apply key function\u001b[39;00m\n\u001b[0;32m   7192\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m key \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m   7193\u001b[0m         \u001b[38;5;66;03m# error: Incompatible types in assignment (expression has type\u001b[39;00m\n\u001b[0;32m   7194\u001b[0m         \u001b[38;5;66;03m# \"Series\", variable has type \"ndarray\")\u001b[39;00m\n",
      "File \u001b[1;32mc:\\Python311\\Lib\\site-packages\\pandas\\core\\generic.py:1911\u001b[0m, in \u001b[0;36mNDFrame._get_label_or_level_values\u001b[1;34m(self, key, axis)\u001b[0m\n\u001b[0;32m   1909\u001b[0m     values \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39maxes[axis]\u001b[38;5;241m.\u001b[39mget_level_values(key)\u001b[38;5;241m.\u001b[39m_values\n\u001b[0;32m   1910\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m-> 1911\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m(key)\n\u001b[0;32m   1913\u001b[0m \u001b[38;5;66;03m# Check for duplicates\u001b[39;00m\n\u001b[0;32m   1914\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m values\u001b[38;5;241m.\u001b[39mndim \u001b[38;5;241m>\u001b[39m \u001b[38;5;241m1\u001b[39m:\n",
      "\u001b[1;31mKeyError\u001b[0m: '低估指标'"
     ]
    },
    {
     "ename": "",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31mThe Kernel crashed while executing code in the current cell or a previous cell. \n",
      "\u001b[1;31mPlease review the code in the cell(s) to identify a possible cause of the failure. \n",
      "\u001b[1;31mClick <a href='https://aka.ms/vscodeJupyterKernelCrash'>here</a> for more info. \n",
      "\u001b[1;31mView Jupyter <a href='command:jupyter.viewOutput'>log</a> for further details."
     ]
    }
   ],
   "source": [
    "import akshare as ak\n",
    "import pandas as pd\n",
    "import datetime\n",
    "\n",
    "industry_df = ak.stock_board_industry_name_ths()\n",
    "industry_list = industry_df['name'].tail(10).tolist()\n",
    "\n",
    "today = datetime.datetime.today()\n",
    "start_date = (today - pd.DateOffset(years=3)).strftime('%Y%m%d')\n",
    "end_date = today.strftime('%Y%m%d')\n",
    "\n",
    "low_industry_list = []\n",
    "\n",
    "for symbol in industry_list:\n",
    "    try:\n",
    "        df = ak.stock_board_industry_index_ths(symbol=symbol, start_date=start_date, end_date=end_date)\n",
    "        df[\"日期\"] = pd.to_datetime(df[\"日期\"])\n",
    "        df = df.sort_values(\"日期\").reset_index(drop=True)\n",
    "        df = df.rename(columns={\"收盘价\": \"close\"})\n",
    "\n",
    "        if len(df) < 150:\n",
    "            continue\n",
    "\n",
    "        df[\"MA120\"] = df[\"close\"].rolling(window=120).mean()\n",
    "\n",
    "        delta = df[\"close\"].diff()\n",
    "        gain = delta.where(delta > 0, 0)\n",
    "        loss = -delta.where(delta < 0, 0)\n",
    "        avg_gain = gain.rolling(window=14).mean()\n",
    "        avg_loss = loss.rolling(window=14).mean()\n",
    "        rs = avg_gain / avg_loss\n",
    "        df[\"RSI14\"] = 100 - (100 / (1 + rs))\n",
    "\n",
    "        current_price = df[\"close\"].iloc[-1]\n",
    "        ma120 = df[\"MA120\"].iloc[-1]\n",
    "        rsi = df[\"RSI14\"].iloc[-1]\n",
    "        quantile_20 = df[\"close\"].quantile(0.2)\n",
    "\n",
    "        if (current_price < ma120) and (current_price < quantile_20) and (rsi < 30):\n",
    "            low_industry_list.append({\n",
    "                \"板块\": symbol,\n",
    "                \"当前价\": round(current_price, 2),\n",
    "                \"MA120\": round(ma120, 2),\n",
    "                \"20%分位\": round(quantile_20, 2),\n",
    "                \"RSI14\": round(rsi, 2),\n",
    "                \"低估指标\": current_price / ma120  # 低估程度指标，值越小越低估\n",
    "            })\n",
    "\n",
    "    except Exception as e:\n",
    "        print(f\"{symbol} 获取失败: {e}\")\n",
    "        continue\n",
    "\n",
    "low_df = pd.DataFrame(low_industry_list)\n",
    "\n",
    "# 按“低估指标”升序排序，取前10个最低的\n",
    "top10_low = low_df.sort_values(\"低估指标\").reset_index(drop=True)\n",
    "\n",
    "print(f\"\\n筛选出最低估的前10个板块：\")\n",
    "print(top10_low)\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
